
#include "stdafx.h"
#include "ConstDef.h"
#include "ReloadCode.h"
#include "ReloadDebugPacket.h"

NodeId::NodeId()
:array_()
{

}

NodeId::NodeId( std::size_t _nodeIdLength, bool _isWildcard )
{
	if(_isWildcard)
		setWildcard(_nodeIdLength);
	else
		setZero(_nodeIdLength);
}

NodeId::NodeId( const NodeId& _nodeId )
:PacketElement(_nodeId)
{
	array_.clear();
	array_.resize(_nodeId.array_.size());
	std::copy(_nodeId.array_.begin(), _nodeId.array_.end(), array_.begin());
}

NodeId::NodeId( std::size_t _bitSet, std::size_t _nodeIdLength )
{
	setBit(_bitSet, _nodeIdLength);
}

NodeId::~NodeId()
{
	array_.clear();
}

retT NodeId::readFromBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
{
	READFROMBUFFER_START;
	array_.clear();
	array_.resize(nodeIdLengthDefault);
	R(_pBuffer->read(&array_[0], array_.size()));
	READFROMBUFFER_END;
}

retT NodeId::writeToBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
{
	WRITETOBUFFER_START;
	R(_pBuffer->write(&array_[0], array_.size()));
	WRITETOBUFFER_END;
}

std::size_t NodeId::size()
{
	return array_.size();
}

std::string NodeId::toString()
{
	if(array_.size() == 0)
		return std::string();
	std::string result;
	asyframe::uint32* pArray = (asyframe::uint32*)&array_[0];
	if(std::size_t i = array_.size()/sizeof(asyframe::uint32))
	{
		do 
		{
			--i;
			result += (boost::format( "%X" ) % pArray[i]).str();
		} while (i != 0);
	}
	return result; 
}

bool NodeId::isZero() const
{
	bool result = true;
	if(array_.size() == 0)
		return true;
	asyframe::uint32* pArray = (asyframe::uint32*)&array_[0];
	for(std::size_t i = 0; i < array_.size()/sizeof(asyframe::uint32); ++i)
	{
		if(pArray[i] != 0)
		{
			result = false;
			break;
		}
	}
	return result;
}

bool NodeId::isWildcard() const
{
	bool result = true;
	if(array_.size() == 0)
		return false;
	asyframe::uint32* pArray = (asyframe::uint32*)&array_[0];
	for(std::size_t i = 0; i < array_.size()/sizeof(asyframe::uint32); ++i)
	{
		if(pArray[i] != ~((asyframe::uint32)0))
		{
			result = false;
			break;
		}
	}
	return result;
}

bool NodeId::isNULL() const
{
	if(array_.size() == 0)
		return true;
	return false;
}

void NodeId::setNULL()
{
	array_.clear();
}

void NodeId::setZero( std::size_t _nodeIdLength )
{
	array_.clear();
	array_.resize(_nodeIdLength);
	asyframe::uint32* pArray = (asyframe::uint32*)&array_[0];
	for(std::size_t i = 0; i < _nodeIdLength/sizeof(asyframe::uint32); i++)
		pArray[i] = 0;
}

void NodeId::setWildcard( std::size_t _nodeIdLength )
{
	array_.clear();
	array_.resize(_nodeIdLength);
	asyframe::uint32* pArray = (asyframe::uint32*)&array_[0];
	for(std::size_t i = 0; i < _nodeIdLength/sizeof(asyframe::uint32); i++)
		pArray[i] = ~((asyframe::uint32)0);
}

void NodeId::setBit( std::size_t _bitSet, std::size_t _nodeIdLength )
{
	setZero(_nodeIdLength);
	_bitSet %= (_nodeIdLength*8);
	array_[_bitSet/(sizeof(asyframe::byte)*8)] = (asyframe::byte)(1 << (_bitSet%(sizeof(asyframe::byte)*8)));
}

const NodeId& NodeId::ZERO( std::size_t _nodeIdLength )
{
	static const NodeId zero128(16),zero160(20);
	if(_nodeIdLength == 20)
		return zero160;
	return zero128;
}

const NodeId& NodeId::WILDCARD( std::size_t _nodeIdLength )
{
	static const NodeId wildcard128(16,true),wildcard160(20,true);
	if(_nodeIdLength == 20)
		return wildcard160;
	return wildcard128;
}

const NodeId& NodeId::BITSET( std::size_t _bitSet, std::size_t _nodeIdLength )
{
	static const class BitSetArray
	{
	public:
		BitSetArray()
		{
			for(std::size_t i = 0; i < 128; ++i)
				bitSet128[i].setBit(i, 16);
			bitSet128[128].setZero(16);
			for(std::size_t i = 0; i < 160; ++i)
				bitSet160[i].setBit(i, 20);
			bitSet160[160].setZero(20);
		}
		NodeId bitSet128[129];
		NodeId bitSet160[161];
	} bitSetArray;
	if(_nodeIdLength == 20)
		return bitSetArray.bitSet160[_bitSet];
	return bitSetArray.bitSet128[_bitSet];
}

const NodeId& NodeId::operator=( const NodeId& _nodeId )
{
	PacketElement::operator=(_nodeId);
	array_.clear();
	array_.resize(_nodeId.array_.size());
	std::copy(_nodeId.array_.begin(), _nodeId.array_.end(), array_.begin());
	return *this;
}

bool operator>( const NodeId& _nodeIdLeft, const NodeId& _nodeIdRight )
{
	std::size_t compCount = (_nodeIdLeft.array_.size()<=_nodeIdRight.array_.size()?_nodeIdLeft.array_.size():_nodeIdRight.array_.size())/sizeof(asyframe::uint32);
	asyframe::uint32* pLeft = (asyframe::uint32*)&_nodeIdLeft.array_[0];
	asyframe::uint32* pRight = (asyframe::uint32*)&_nodeIdRight.array_[0];
	bool result = false;
	for(int i = compCount - 1; i >= 0; --i)
	{
		if(pLeft[i] == pRight[i])
		{
			continue;
		}
		else if(pLeft[i] > pRight[i])
		{
			result = true;
			break;
		}
		else
		{
			result = false;
			break;
		}
	}
	return result;
}

bool operator==( const NodeId& _nodeIdLeft, const NodeId& _nodeIdRight )
{
	if(_nodeIdLeft.array_.size() != _nodeIdRight.array_.size())
		return false;
	std::size_t compCount = _nodeIdLeft.array_.size()/sizeof(asyframe::uint32);
	asyframe::uint32* pLeft = (asyframe::uint32*)&_nodeIdLeft.array_[0];
	asyframe::uint32* pRight = (asyframe::uint32*)&_nodeIdRight.array_[0];
	bool result = true;
	for(int i = compCount - 1; i >= 0; --i)
	{
		if(pLeft[i] != pRight[i])
		{
			result = false;
			break;
		}
	}
	return result;
}

bool operator!=( const NodeId& _nodeIdLeft, const NodeId& _nodeIdRight )
{
	return !(_nodeIdLeft==_nodeIdRight);
}

bool operator<( const NodeId& _nodeIdLeft, const NodeId& _nodeIdRight )
{
	return !(_nodeIdLeft>=_nodeIdRight);
}

bool operator>=( const NodeId& _nodeIdLeft, const NodeId& _nodeIdRight )
{
	return _nodeIdLeft>_nodeIdRight||_nodeIdLeft==_nodeIdRight;
}

bool operator<=( const NodeId& _nodeIdLeft, const NodeId& _nodeIdRight )
{
	return _nodeIdLeft<_nodeIdRight||_nodeIdLeft==_nodeIdRight;
}

NodeId operator~( const NodeId& _nodeId )
{
	std::size_t compCount = _nodeId.array_.size()/sizeof(asyframe::uint32);
	asyframe::uint32* pArray = (asyframe::uint32*)&_nodeId.array_[0];
	NodeId result;
	result.array_.resize(_nodeId.array_.size());
	asyframe::uint32* pResult = (asyframe::uint32*)&result.array_[0];
	for(std::size_t i = 0; i < compCount; ++i)
	{
		pResult[i] = ~pArray[i];
	}
	return result;
}

NodeId operator+( const NodeId& _nodeIdLeft, const NodeId& _nodeIdRight )
{
	if(_nodeIdLeft.array_.size() != _nodeIdRight.array_.size())
		return _nodeIdLeft;
	std::size_t compCount = _nodeIdLeft.array_.size()/sizeof(asyframe::uint32);
	asyframe::uint32* pLeft = (asyframe::uint32*)&_nodeIdLeft.array_[0];
	asyframe::uint32* pRight = (asyframe::uint32*)&_nodeIdRight.array_[0];
	NodeId result;
	result.array_.resize(_nodeIdLeft.array_.size());
	asyframe::uint32* pResult = (asyframe::uint32*)&result.array_[0];
	asyframe::uint32 c = 0;
	for(std::size_t i = 0; i < compCount; ++i)
	{
		pResult[i] = pLeft[i] + pRight[i] + c;
		if(c == 0)
		{
			if(pResult[i] < pLeft[i])
				c = 1;
		}
		else
		{
			if(pResult[i] > pLeft[i])
				c = 0;
		}
	}
	return result;
}

NodeId operator-( const NodeId& _nodeIdLeft, const NodeId& _nodeIdRight )
{
	if(_nodeIdLeft.array_.size() != _nodeIdRight.array_.size())
		return _nodeIdLeft;
	return _nodeIdLeft+~_nodeIdRight+NodeId::BITSET(0, _nodeIdLeft.array_.size());
}

std::size_t hash_value( NodeId const& _nodeId )
{
	boost::hash<std::size_t> shasher;
	if(_nodeId.array_.size() == 0)
		return 0;
	std::size_t* pArray = (std::size_t*)(&_nodeId.array_[0]);
	std::size_t result = shasher(pArray[0]);
	for(std::size_t i = 1; i < _nodeId.array_.size()/sizeof(std::size_t); ++i)
	{
		result ^= shasher(pArray[i]);
	}
	return result;
}

////////////////////////////////////////////////////////////////////////////////////

IPv4AddrPort::IPv4AddrPort()
:addr_(),port_(0)
{

}

IPv4AddrPort::~IPv4AddrPort()
{
	port_ = 0;
}

retT IPv4AddrPort::readFromBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
{
	READFROMBUFFER_START;
	asyframe::uint32 addr;
	R(_pBuffer->ntohRead(addr));
	addr_ = boost::asio::ip::address_v4(addr);
	R(_pBuffer->ntohRead(port_));
	READFROMBUFFER_END;
}

retT IPv4AddrPort::writeToBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
{
	WRITETOBUFFER_START;
	R(_pBuffer->htonWrite((asyframe::uint32)addr_.to_ulong()));
	R(_pBuffer->htonWrite(port_));
	WRITETOBUFFER_END;
}

std::size_t IPv4AddrPort::size()
{
	return sizeof(asyframe::uint32) + sizeof(port_);
}

////////////////////////////////////////////////////////////////////////////////////////////

IPv6AddrPort::IPv6AddrPort()
:addr_(),port_(0)
{

}

IPv6AddrPort::~IPv6AddrPort()
{
	port_ = 0;
}

retT IPv6AddrPort::readFromBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
{
	READFROMBUFFER_START;
	boost::asio::ip::address_v6::bytes_type addr;
	R(_pBuffer->read(addr.c_array(), sizeof(boost::asio::ip::address_v6::bytes_type)));
	addr_ = boost::asio::ip::address_v6(addr);
	R(_pBuffer->ntohRead(port_));
	READFROMBUFFER_END;
}

retT IPv6AddrPort::writeToBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
{
	WRITETOBUFFER_START;
	R(_pBuffer->write(addr_.to_bytes().c_array(), sizeof(boost::asio::ip::address_v6::bytes_type)));
	R(_pBuffer->htonWrite(port_));
	WRITETOBUFFER_END;
}

std::size_t IPv6AddrPort::size()
{
	return sizeof(boost::asio::ip::address_v6::bytes_type) + sizeof(port_);
}

//////////////////////////////////////////////////////////////////////////////////////////////

IpAddressPort::IpAddressPort()
:type_(AddressType_ReservedAddr),length_(0),port_(0)
{

}

IpAddressPort::IpAddressPort( const boost::asio::ip::address& _addr, asyframe::uint16 _port )
:type_(AddressType_ReservedAddr),length_(0),addr_(_addr),port_(_port)
{
	if(addr_.is_v4())
		type_ = AddressType_Ipv4Address;
	else if(addr_.is_v6())
		type_ = AddressType_Ipv6Address;
	else
		return;
	length_ = size() - sizeof(type_) - sizeof(length_);
}

IpAddressPort::~IpAddressPort()
{
	type_ = AddressType_ReservedAddr;
	length_ = 0;
	port_ = 0;
}

retT IpAddressPort::readFromBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
{
	READFROMBUFFER_START;
	R(_pBuffer->ntohRead(type_));
	R(_pBuffer->ntohRead(length_));
	switch(type_)
	{
	case AddressType_Ipv4Address:
		{
			IPv4AddrPort       v4AddrPort;
			R(v4AddrPort.readFromBuffer(_pBuffer));
			addr_ = v4AddrPort.addr_;
			port_ = v4AddrPort.port_;
			break;
		}
	case AddressType_Ipv6Address:
		{
			IPv6AddrPort       v6AddrPort;
			R(v6AddrPort.readFromBuffer(_pBuffer));
			addr_ = v6AddrPort.addr_;
			port_ = v6AddrPort.port_;
			break;
		}
	default:R(_pBuffer->consume(length_));RET(INFO_PROTOCOL_RELOAD_IPADDRESSPORT_UNKNOWN_TYPE);
	}
	READFROMBUFFER_END;
}

retT IpAddressPort::writeToBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
{
	WRITETOBUFFER_START;
	R(_pBuffer->htonWrite(type_));
	length_ = size() - sizeof(type_) - sizeof(length_);
	R(_pBuffer->htonWrite(length_));
	switch(type_)
	{
	case AddressType_Ipv4Address:
		{
			IPv4AddrPort       v4AddrPort;
			v4AddrPort.addr_ = addr_.to_v4();
			v4AddrPort.port_ = port_;
			v4AddrPort.writeToBuffer(_pBuffer);
			break;
		}
	case AddressType_Ipv6Address:
		{
			IPv6AddrPort       v6AddrPort;
			v6AddrPort.addr_ = addr_.to_v6();
			v6AddrPort.port_ = port_;
			v6AddrPort.writeToBuffer(_pBuffer);
			break;
		}
	default:R(_pBuffer->produce(length_));RET(INFO_PROTOCOL_RELOAD_IPADDRESSPORT_UNKNOWN_TYPE);
	}
	WRITETOBUFFER_END;
}

std::size_t IpAddressPort::size()
{
	std::size_t totalSize = 0;
	totalSize += sizeof(type_);
	totalSize += sizeof(length_);
	switch(type_)
	{
	case AddressType_Ipv4Address:
		{
			IPv4AddrPort       v4AddrPort;
			v4AddrPort.addr_ = addr_.to_v4();
			v4AddrPort.port_ = port_;
			totalSize += v4AddrPort.size();
			break;
		}
	case AddressType_Ipv6Address:
		{
			IPv6AddrPort       v6AddrPort;
			v6AddrPort.addr_ = addr_.to_v6();
			v6AddrPort.port_ = port_;
			totalSize += v6AddrPort.size();
			break;
		}
	default:totalSize += length_;
	}
	return totalSize;
}

std::size_t hash_value( IpAddressPort const& _ipAddressPort )
{
	IpAddressPort ipAddressPort(_ipAddressPort);
	boost::hash<std::size_t> shasher;
	std::vector<asyframe::byte> vecBuf;
	vecBuf.resize((ipAddressPort.size()/sizeof(std::size_t) + 1) * sizeof(std::size_t), 0);
	boost::shared_ptr<asyframe::IoBuffer> pBuffer(new asyframe::IoBuffer(&vecBuf));
	ipAddressPort.writeToBuffer(pBuffer);
	if(vecBuf.size() == 0)
		return 0;
	std::size_t* pArray = (std::size_t*)(&vecBuf[0]);
	std::size_t result = shasher(pArray[0]);
	for(std::size_t i = 1; i < vecBuf.size()/sizeof(std::size_t); ++i)
	{
		result ^= shasher(pArray[i]);
	}
	return result;
}

bool operator==( const IpAddressPort& _ipAddressPortLeft, const IpAddressPort& _ipAddressPortRight )
{
	if(_ipAddressPortLeft.type_ != _ipAddressPortRight.type_)
		return false;
	if(_ipAddressPortLeft.length_ != _ipAddressPortRight.length_)
		return false;
	if(_ipAddressPortLeft.addr_ != _ipAddressPortRight.addr_)
		return false;
	if(_ipAddressPortLeft.port_ != _ipAddressPortRight.port_)
		return false;
	return true;
}

///////////////////////////////////////////////////////////////////////////////////////////

NodeInfo::NodeInfo()
{

}

NodeInfo::~NodeInfo()
{

}

retT NodeInfo::readFromBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
{
	READFROMBUFFER_START;
	R(nodeId_.readFromBuffer(_pBuffer));
	R(ipAddressPort_.readFromBuffer(_pBuffer));
	READFROMBUFFER_END;
}

retT NodeInfo::writeToBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
{
	WRITETOBUFFER_START;
	R(nodeId_.writeToBuffer(_pBuffer));
	R(ipAddressPort_.writeToBuffer(_pBuffer));
	WRITETOBUFFER_END;
}

std::size_t NodeInfo::size()
{
	return nodeId_.size() + ipAddressPort_.size();
}

////////////////////////////////////////////////////////////////////////////////////////////

ChordInfoDebugPacket::ChordInfoDebugPacket()
{

}

ChordInfoDebugPacket::~ChordInfoDebugPacket()
{

}

retT ChordInfoDebugPacket::readFromBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
{
	READFROMBUFFER_START;
	R(selfNodeInfo_.readFromBuffer(_pBuffer));
	R(predecessors_.readFromBuffer(_pBuffer));
	R(successors_.readFromBuffer(_pBuffer));
	R(fingers_.readFromBuffer(_pBuffer));
	READFROMBUFFER_END;
}

retT ChordInfoDebugPacket::writeToBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
{
	WRITETOBUFFER_START;
	R(selfNodeInfo_.writeToBuffer(_pBuffer));
	R(predecessors_.writeToBuffer(_pBuffer));
	R(successors_.writeToBuffer(_pBuffer));
	R(fingers_.writeToBuffer(_pBuffer));
	WRITETOBUFFER_END;
}

std::size_t ChordInfoDebugPacket::size()
{
	return selfNodeInfo_.size() + predecessors_.size() + successors_.size() + fingers_.size();
}

////////////////////////////////////////////////////////////////////////////////////////////////

DataStorageInfoDebugPacket::DataStorageInfoDebugPacket()
:nonReplica_(0),replica1_(0),replica2_(0),unknownReplica_(0)
{

}

DataStorageInfoDebugPacket::~DataStorageInfoDebugPacket()
{
	nonReplica_ = 0;
	replica1_ = 0;
	replica2_ = 0;
	unknownReplica_ = 0;
}

retT DataStorageInfoDebugPacket::readFromBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
{
	READFROMBUFFER_START;
	R(_pBuffer->ntohRead(nonReplica_));
	R(_pBuffer->ntohRead(replica1_));
	R(_pBuffer->ntohRead(replica2_));
	R(_pBuffer->ntohRead(unknownReplica_));
	READFROMBUFFER_END;
}

retT DataStorageInfoDebugPacket::writeToBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
{
	WRITETOBUFFER_START;
	R(_pBuffer->htonWrite(nonReplica_));
	R(_pBuffer->htonWrite(replica1_));
	R(_pBuffer->htonWrite(replica2_));
	R(_pBuffer->htonWrite(unknownReplica_));
	WRITETOBUFFER_END;
}

std::size_t DataStorageInfoDebugPacket::size()
{
	return sizeof(nonReplica_) + sizeof(replica1_) + sizeof(replica2_) + sizeof(unknownReplica_);
}
